﻿using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using SpicIE.Common;

namespace SpicIE.Controls
{
    /// <summary>
    /// Creates a new button in the tools menu of the internet explorer
    /// </summary>
    public abstract class ToolbarButton : IControlBase, IOleCommandTarget
    {
        /// <summary>
        /// The PluginGuid _must_ be a unique GUID to identify and register the COM object correctly
        /// </summary>
        public abstract string PluginGuid { get; }
        /// <summary>
        /// The PluginProgID _must_ be provided to identify and register the COM object correctly
        /// </summary>
        public abstract string PluginProgID { get; }

        #region Member variables declaration

        public Guid ButtonID { get { return new Guid(PluginGuid); } }
        public string ButtonProgID { get { return PluginProgID; } }

        protected Guid AssociatedBandObjectID;
        protected Guid AssociatedCLSIDExtension;
        protected string ButtonName;
        protected string ButtonText;
        protected string HotIconPath;
        protected string IconPath;
        protected string ExecutePath;
        protected string MenuStatusBar;
        protected string MenuText;
        protected bool DefaultVisibility;

        public Guid BandObjectID { get { return AssociatedBandObjectID; } }
        public Guid CLSIDExtension { get { return AssociatedCLSIDExtension; } }
        public string ToolbarButtonName { get { return ButtonName; } }
        public string ToolbarButtonText { get { return ButtonText; } }
        public string ToolbarHotIconPath { get { return HotIconPath; } }
        public string ToolbarIconPath { get { return IconPath; } }
        public string ToolbarExecutePath { get { return ExecutePath; } }
        public string ToolbarMenuStatusBar { get { return MenuStatusBar; } }
        public string ToolbarMenuText { get { return MenuText; } }
        public bool ToolbarDefaultVisibility { get { return DefaultVisibility; } }

        /// <summary>
        /// Specifies wether the button should appear in the tools menu or the help menu
        /// </summary>
        [ComVisible(false)]
        public ButtonCustomEnum ButtomCustomMenu = ButtonCustomEnum.Tools;
        
        /// <summary>
        /// Lets the user decide in which way the button should behave. 
        /// Either opening a COMObject, executing a script or an application
        /// </summary>
        [ComVisible(false)]
        public ButtonAppearanceEnum ButtonAppearance;

        /// <summary>
        /// Specifies where the menu item should appear
        /// </summary>
        public enum ButtonCustomEnum
        {
            Tools = 1,
            Help = 2
        }

        #endregion

        /// <summary>
        /// Delegate event which can be subscribed when intantiating the class
        /// </summary>
        /// <param name="value">the return value from the handle, default -1</param>
        public delegate void OLECommand(int value);
        public event OLECommand OnButtonCommand;

        /// <summary>
        /// Specifies the behaviour of the toolbar button
        /// </summary>
        public enum ButtonAppearanceEnum
        {
            COMObject = 1,
            Executables = 2
        }

        #region COM object register functionality
        /// <summary>
        /// Global function for registering the com object
        /// </summary>
        public void Register()
        {
            Host.TraceSink.TraceInformation("SpicIE: before registering ToolbarButton " + ToolbarButtonName);

            try
            {
                string id = ButtonID.ToString("B");

                if (ToolbarButtonName == string.Empty)
                    return;

                Host.RegisterCOMObject(GetType(), ButtonID, ButtonProgID);

                RegistryKey mainKey = Registry.LocalMachine.CreateSubKey(Constants.REGISTRY_TOOLBARBUTTON + id);

                if (mainKey != null)
                {
                    if (!String.IsNullOrEmpty(ToolbarButtonText)) mainKey.SetValue("ButtonText", ToolbarButtonText);
                    if (!String.IsNullOrEmpty(ToolbarMenuText)) mainKey.SetValue("MenuText", ToolbarMenuText);
                    if (!String.IsNullOrEmpty(ToolbarMenuStatusBar)) mainKey.SetValue("MenuStatusBar", ToolbarMenuStatusBar);
                    if (!String.IsNullOrEmpty(ToolbarMenuStatusBar)) mainKey.SetValue("ToolTip", ToolbarMenuStatusBar);
                    if (!String.IsNullOrEmpty(ToolbarHotIconPath)) mainKey.SetValue("HotIcon", ToolbarHotIconPath);
                    if (!String.IsNullOrEmpty(ToolbarIconPath)) mainKey.SetValue("Icon", ToolbarIconPath);

                    if (ButtomCustomMenu == ButtonCustomEnum.Help)
                    {
                        mainKey.SetValue("MenuCustomize", "help");
                    }
                    else
                    {
                        mainKey.SetValue("MenuCustomize", "tools");
                    }

                    if (!ToolbarDefaultVisibility)
                        mainKey.SetValue("Default Visible", "No");
                    else
                        mainKey.SetValue("Default Visible", "Yes");

                    switch (ButtonAppearance)
                    {
                        case ButtonAppearanceEnum.COMObject:
                            mainKey.SetValue("CLSID", "{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}");
                            mainKey.SetValue("ClsidExtension", CLSIDExtension.ToString("B"));
                            break;
                        case ButtonAppearanceEnum.Executables:
                            mainKey.SetValue("CLSID", "{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}");
                            mainKey.SetValue("Exec", ToolbarExecutePath);
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                Host.TraceSink.TraceEvent(TraceEventType.Error, 0, "Exception:Registering ToolbarButton " + ToolbarButtonName + ": " + ex);
            }

            Host.TraceSink.TraceInformation("SpicIE: after registering ToolbarButton " + ToolbarButtonName);
        }

        /// <summary>
        /// Global function for unregistering the com object
        /// </summary>
        public void Unregister()
        {
            Host.TraceSink.TraceInformation("SpicIE: before unregistering ToolbarButton " + ToolbarButtonName);

            try
            {
                string id = ButtonID.ToString("B");

                Host.UnRegisterCOMObject(ButtonID);

                if (Registry.LocalMachine.OpenSubKey(Constants.REGISTRY_TOOLBARBUTTON + id) != null)
                    Registry.LocalMachine.DeleteSubKey(Constants.REGISTRY_TOOLBARBUTTON + id);
            }
            catch( Exception ex )
            {
                Host.TraceSink.TraceEvent(TraceEventType.Error, 0, "Exception: Unregistering ToolbarButton " + ToolbarButtonName + ": " + ex);
            }

            Host.TraceSink.TraceInformation("SpicIE: after unregistering ToolbarButton " + ToolbarButtonName);
        }
        #endregion

        #region IOLECommandTarget interface implementation
        /// <summary>
        /// interface implementation for communicating with the ole object, in this case the menuitem as com object
        /// </summary>
        /// <param name="pguidCmdGroup"></param>
        /// <param name="cCmds"></param>
        /// <param name="prgCmds"></param>
        /// <param name="pCmdText"></param>
        /// <returns>-1</returns>
        [CLSCompliant(false)]
        public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
        {
            return -1;
        }

        /// <summary>
        /// interface implementation for firing the OLE Command event which can be subscribed in the intatiated class
        /// </summary>
        /// <param name="pguidCmdGroup"></param>
        /// <param name="nCmdID"></param>
        /// <param name="nCmdexecopt"></param>
        /// <param name="pvaIn"></param>
        /// <param name="pvaOut"></param>
        /// <returns>-1</returns>
        [CLSCompliant(false)]
        public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
            if (OnButtonCommand != null) 
                OnButtonCommand(Convert.ToInt32(nCmdID));

            return -1;
        }
        #endregion
    }
}
